package com.spzx.gateway.filter;

import java.util.Collections;
import java.util.List;

import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 获取body请求数据（解决流不能重复读取问题）
 *
 * 该过滤器用于缓存HTTP请求体，以便在后续处理中可以多次读取请求体内容。
 * 主要解决了GET和POST等方法中请求体只能被读取一次的问题。
 *
 * @author spzx
 */
@Component
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
{
    /**
     * 构造函数，初始化父类并指定配置类类型。
     */
    public CacheRequestFilter()
    {
        super(Config.class);
    }

    /**
     * 返回过滤器的名称。
     *
     * @return 过滤器名称字符串
     */
    @Override
    public String name()
    {
        return "CacheRequestFilter";
    }

    /**
     * 应用配置并返回一个GatewayFilter实例。
     *
     * 如果配置中指定了顺序值，则返回一个有序的GatewayFilter；
     * 否则返回一个普通的GatewayFilter。
     *
     * @param config 过滤器的配置对象
     * @return GatewayFilter实例
     */
    @Override
    public GatewayFilter apply(Config config)
    {
        CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
        Integer order = config.getOrder();
        if (order == null)
        {
            return cacheRequestGatewayFilter;
        }
        return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
    }

    /**
     * 实现GatewayFilter接口，用于缓存请求体和请求。
     */
    public static class CacheRequestGatewayFilter implements GatewayFilter
    {
        /**
         * 过滤方法，处理传入的ServerWebExchange和过滤链。
         * 对于GET和DELETE请求，直接传递给下一个过滤器，不进行任何处理。
         * 对于其他方法（如POST、PUT等），缓存请求体，并将其传递给下一个过滤器。
         *
         * @param exchange 服务器Web交换对象
         * @param chain    过滤链对象
         * @return Mono<Void>，表示异步操作完成
         */
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            // 对于GET和DELETE请求，直接传递给下一个过滤器，不进行任何处理
            HttpMethod method = exchange.getRequest().getMethod();
            if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
            {
                return chain.filter(exchange);
            }

            // 缓存请求体，并将其传递给下一个过滤器
            return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
                if (serverHttpRequest == exchange.getRequest())
                {
                    return chain.filter(exchange);
                }
                return chain.filter(exchange.mutate().request(serverHttpRequest).build());
            });
        }
    }

    /**
     * 返回快捷字段顺序列表，用于简化配置。
     *
     * @return 字段顺序列表
     */
    @Override
    public List<String> shortcutFieldOrder()
    {
        return Collections.singletonList("order");
    }

    /**
     * 配置类，用于定义过滤器的顺序。
     */
    @Setter
    @Getter
    static class Config
    {
        /**
         * -- GETTER --
         *  获取顺序值。
         * -- SETTER --
         *  设置顺序值。
         *
         */
        private Integer order;

    }
}
